#include "ActionApiReportTicketInfo.h"
#include "json.h"
#include "util.h"
#include "streamdata.h"
#include "agency_event_service.h"
#include "agencyeventmgr.h"
#include "3400_api_order.pb.h"
#include "api_order_service.h"
#include "flow_service.h"
#include "agencyevent.h"

static const std::int32_t MAX_OPTICKT_NUM = 100;

static std::map<std::string,std::string> http_json_heads = {{"Content-Type","application/json"}};

static bool __init__ = ActionApiReportTicketInfo::Init();

bool ActionApiReportTicketInfo::Init()
{
    Ctx.msg_router.BindMsg(agency_event_api::AGENCY_EVENT_API_MSGID_REPORT_TICKET_INFO_REQ, ActionApiReportTicketInfo::HandleReportTicketInfo);
    AgencyEventService::Instance()->ListenOnAgencyEventGet(AgencyEventService::REPORTTICKET, ActionApiReportTicketInfo::OnAgencyGet);

    return true;
}

void ActionApiReportTicketInfo::HandleReportTicketInfo(MsgData&& msg_data)
{
    agency_event_api::ReportTicketInfoReq req;
    agency_event_api::ReportTicketInfoResp resp;

    do {
        if (!req.ParseFromArray(msg_data.data.data(), msg_data.data.size()))
        {
            resp.set_errorcode(agency_event_api::ErrorCode::DataParseErr);
            log_error("parser msg failed");
            break;
        }
        
        if (req.ticketlist_size() > MAX_OPTICKT_NUM)
        {
            resp.set_errorcode(agency_event_api::ErrorCode::InvaildParam);
            log_error("ticketlist size too many, size: %d", req.ticketlist_size());
            break;
        }

        log_debug("req:%s", req.ShortDebugString().c_str());

        stAgencyEvent* agency = AgencyEventMgr::Instance()->Get(req.agency_id());
        if (agency != nullptr)
        {
            if (!AgencyEventMgr::Instance()->CheckAgencyEventActive(agency))
            {
                resp.set_errorcode(agency_event_api::ErrorCode::MatchForbidErr);
                log_error("match forbid, agenevent=%s", agency->ToString().c_str());
                break;
            }

            Request(agency->call_url,
                req.uid(), msg_data.svtype, msg_data.svid, msg_data.uuid, agency->agency_name,
                req);
        }
        else
        {
            StreamData stream_data;
            StreamDataWriter writer(stream_data);
            writer.WriteShort(msg_data.svtype);
            writer.WriteInt(msg_data.svid);
            writer.WriteInt(msg_data.uuid);
            writer.WriteInt(req.uid());
            // 写字符串
            writer.WriteInt(msg_data.data.size());
            writer.WriteBinary(msg_data.data.data(), msg_data.data.size());
            
            if (!AgencyEventService::Instance()->HandleGetAgencyEvent(req.agency_id(), std::move(stream_data.Data()), AgencyEventService::REPORTTICKET))
            {
                resp.set_errorcode(agency_event_api::ErrorCode::AgentGetErr);
                log_error("parser msg failed");
                break;
            }
        }
        return;
    } while(false);

    if (resp.errorcode() != 0)
    {
        // 回包
        resp.set_uid(req.uid());
        resp.set_message(ToString(resp.errorcode()));
        Ctx.host->MtSendtoOneSrv(agency_event_api::AGENCY_EVENT_API_MSGID_REPORT_TICKET_INFO_RESP, &resp, msg_data.svtype, msg_data.svid, false, msg_data.uuid);
    }
}

void ActionApiReportTicketInfo::OnAgencyGet(std::int32_t err_code, stAgencyEvent* agency, std::string&& trans)
{
    StreamData stream_data(std::move(trans));
    StreamDataReader reader(stream_data);
    std::uint16_t svtype = reader.ReadShort();
    std::uint32_t svid = reader.ReadInt();
    std::uint32_t uuid = reader.ReadInt();
    std::uint32_t uid = reader.ReadInt();
    std::string msg_data = reader.ReadString();
    
    agency_event_api::MatchRewardResp resp;
    do
    {
        if (err_code != 0)
        {
            resp.set_errorcode(agency_event_api::ErrorCode::AgencyGetErr);
            log_error("get account info failed,uid:%u,err_code:%d", uid, err_code);
            break;
        }
        if (agency == nullptr)
        {
            resp.set_errorcode(agency_event_api::ErrorCode::AgencyGetErr);
            log_error("account is nullptr,uid:%u,err_code:%d", uid, err_code);
            break;
        }
        agency_event_api::ReportTicketInfoReq req;
        if (!req.ParseFromArray(msg_data.c_str(), msg_data.size()))
        {
            resp.set_errorcode(agency_event_api::ErrorCode::DataParseErr);
            log_error("parser msg failed");
            break;
        }
		log_debug("agency:%s", agency->ToString().c_str());

        Request(agency->call_url,
            req.uid(), svtype, svid, uuid, agency->agency_name,
            req);
        return;
    } while(false);

    if (resp.errorcode() != 0)
    {
        // 回包
        resp.set_uid(uid);
        resp.set_message(ToString(resp.errorcode()));
        Ctx.host->MtSendtoOneSrv(agency_event_api::AGENCY_EVENT_API_MSGID_REPORT_TICKET_INFO_RESP, &resp, svtype, svid, false, uuid);
    }
}

void ActionApiReportTicketInfo::Request(const std::string& baseurl, std::uint32_t uid, std::uint16_t svtype, std::uint32_t svid, std::uint32_t uuid, const std::string& agency,
        agency_event_api::ReportTicketInfoReq& req)
{
    agency_event_api::MatchRewardResp resp;
    do
    {
        std::string req_id = GenTransId();
        std::uint64_t now = CTools::GetUnixTime();

        Json::Value http_req;
        http_req["reqId"] = req_id;
        http_req["username"] = req.username();
        http_req["agency"] = agency;
        http_req["ticketnum"] = req.ticket_num();
        http_req["allticketnum"] = req.ticket_all_num();

        Json::Value ticketList;
        for (int i = 0; i < req.ticketlist_size(); i++)
        {
            const agency_event_api::TicketInfo& ticketInfo = req.ticketlist(i);
            Json::Value ticketInfoValue;
            ticketInfoValue["ticketid"] = ticketInfo.ticket_id();
            ticketInfoValue["entityid"] = Json::Int64(ticketInfo.entity_id());
            ticketInfoValue["expiretime"] = Json::Int64(ticketInfo.end_ticket_timestamp());
            ticketInfoValue["ticketname"] = ticketInfo.ticket_name();

            ticketList.append(ticketInfoValue);
        }
        http_req["ticketlist"] = ticketList;
        
        Json::Value methodInfoValue;
        const agency_event_api::MethodInfo& methodInfo = req.alter_method();
        methodInfoValue["altertype"] = methodInfo.alter_type();
        methodInfoValue["id"] = Json::Int64(methodInfo.id());
        methodInfoValue["optime"] = Json::Int64(methodInfo.alter_timestamp());
        methodInfoValue["round"] = Json::Int64(methodInfo.order_id());
        http_req["altermethod"] = methodInfoValue;

        http_req["wagersTime"] = Json::UInt64(now);

        std::string json_string = CTools::ToStr(http_req);
        std::string url = baseurl + "/reportTicketInfo";

        api_order::ApiOrder api_order;
        api_order.set_scene_from(agency_event_api::FromGame);
        api_order.set_stype_from(svtype);
        api_order.set_svid_from(svid);
        api_order.set_uid(uid);
        api_order.set_username(req.username());
        api_order.set_agency(agency);
        api_order.set_op(api_order::API_ORDER_OP_REPORTTICKETINFO);
        api_order.set_url(url);
        api_order.set_req_id(req_id);
        api_order.set_req_body(json_string);
        api_order.set_start_time(now);
        api_order.set_update_time(now);

        std::uint32_t event_id = 0;
        // 请求http网络
        if (!Ctx.msg_router.sendHttpPOST(url, json_string, http_json_heads, event_id) || (event_id == 0))
        {
            resp.set_errorcode(agency_event_api::ErrorCode::SendPostErr);
            log_error("net post failed,url:%s,param:%s", url.c_str(),json_string.c_str());
            break;
        }
        log_debug("http post,url:%s,param:%s", url.c_str(), json_string.c_str());
        // 添加回调监听
        Ctx.msg_router.AddCurlEvent(event_id, [uid, svtype, svid, uuid,
            url=std::move(url), json_string= std::move(json_string), api_order_v = std::move(api_order)](std::string& body, bool is_ok){
            agency_event_api::MatchRewardResp resp;
            Json::Value http_resp;
            
            std::uint64_t now = CTools::GetUnixTime();

            api_order::ApiOrder api_order = std::move(api_order_v);
            api_order.set_update_time(now);
            api_order.set_resp_body(body);
            do
            {
                // 网络错误
                if (!is_ok)
                {
                    resp.set_errorcode(agency_event_api::ErrorCode::RespTimeout);
                    log_error("time out,url:%s,param:%s", url.c_str(), json_string.c_str());
                    break;
                }
                
                // 解析返回格式
                if (!CTools::FromStr(http_resp, body))
                {
                    // resp.set_errorcode(agency_event_api::ErrorCode::DataParseErr);
                    resp.set_errorcode(agency_event_api::ErrorCode::RespTimeout);
                    log_error("resp from json failed, body:%s ,url:%s,param:%s", body.c_str(), url.c_str(), json_string.c_str());
                    break;
                }

                if (!http_resp.isMember("errorCode") || !http_resp["errorCode"].isInt())
                {
                    resp.set_errorcode(agency_event_api::ErrorCode::InvaildParam);
                    log_error("response param invalid, body:%s ,url:%s,param:%s", body.c_str(), url.c_str(), json_string.c_str());
                    break;
                }

                resp.set_errorcode(http_resp["errorCode"].asInt());
                std::int64_t txid = 0;
                if (http_resp.isMember("txId") && http_resp["txId"].isInt64()) 
                {
                    txid = http_resp["txId"].asInt64();
                }
                
                api_order.set_resp_id(txid);
            } while (false);
            
            // 回包
            resp.set_uid(uid);
            log_debug("resp:%s", resp.ShortDebugString().c_str());

            Ctx.host->MtSendtoOneSrv(agency_event_api::AGENCY_EVENT_API_MSGID_REPORT_TICKET_INFO_RESP, &resp, svtype, svid, false, uuid);
            
            // 订单更新
            api_order.set_err_code(resp.errorcode());
            ApiOrderService::Instance()->OnApiOrderUpdate(api_order);
        });

        return;
    } while(false);

    if (resp.errorcode() != 0)
    {
        // 回包
        resp.set_uid(uid);
        Ctx.host->MtSendtoOneSrv(agency_event_api::AGENCY_EVENT_API_MSGID_REPORT_TICKET_INFO_RESP, &resp, svtype, svid, false, uuid);
    }
}
